﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using HYRevitCode.RevitObjectCompareUtility;
using YJKRGeometry;
using TopologySearch;

namespace YJKArchMethodLibrary.StructurePoleSuit
{
	public class StructureLoopSearcher
	{
		public StructureLoopSearcher(ExternalCommandData commandData, bool isSearchEdgeLoops)
		{
			this.m_Revit = commandData;
			this.m_IsSearchEdgeLoops = isSearchEdgeLoops;
		}

		public List<Curve> GetEdgeLoopsByEdgeList(List<Curve> curveList)
		{
			List<List<Curve>> list = new List<List<Curve>>();
			list = this.GetFullFloorEdgeLoops(curveList);
			if (list.Count > 0)
			{
				return list[0];
			}
			return new List<Curve>();
		}

		public List<List<Curve>> GetFullFloorEdgeLoops(List<Curve> edgeList)
		{
			new List<List<Curve>>();
			List<Pole2D> list = new List<Pole2D>();
			foreach (Curve curve in edgeList)
			{
				Pole2D item = Pole2D.TransformWallToStructure2DPole(curve, ElementId.InvalidElementId, 0.0, 0.0);
				list.Add(item);
			}
			double dEps = 0.001;
            return new TopologySearch.StructureLoopSearcher(this.m_Revit, dEps).GetFullFloorEdgeLoops(list, TopologySearch.StructureLoopSearcher.SearchEdgeLocation.SEL_Outside);
		}

		protected void InitData(List<Structure2DPole> poleList, ref List<Structure2DNode> theNodes)
		{
			Dictionary<XYZ, Structure2DNode> dictionary = new Dictionary<XYZ, Structure2DNode>(new XYZEqualityComparer());
			foreach (Structure2DPole structure2DPole in poleList)
			{
				XYZ xyz = structure2DPole.StartPoint;
				if (!dictionary.ContainsKey(xyz))
				{
					Structure2DNode value = new Structure2DNode(xyz, new List<Structure2DPole>
					{
						structure2DPole
					});
					dictionary.Add(xyz, value);
				}
				else
				{
					dictionary[xyz].AddPole(structure2DPole);
				}
				xyz = structure2DPole.EndPoint;
				if (!dictionary.ContainsKey(xyz))
				{
					Structure2DNode value2 = new Structure2DNode(xyz, new List<Structure2DPole>
					{
						structure2DPole
					});
					dictionary.Add(xyz, value2);
				}
				else
				{
					dictionary[xyz].AddPole(structure2DPole);
				}
			}
			foreach (KeyValuePair<XYZ, Structure2DNode> keyValuePair in dictionary)
			{
				keyValuePair.Value.AnticlockwiseSortElements();
				theNodes.Add(keyValuePair.Value);
			}
		}

		protected void TrimOneNode(Structure2DNode node)
		{
			int count = node.PoleList.Count;
			if (count == 1)
			{
				return;
			}
			node.AnticlockwiseSortElements();
			List<Structure2DPole> poleList = node.PoleList;
			for (int i = 0; i < count; i++)
			{
				int index = i;
				int index2 = i + 1;
				if (i == count - 1)
				{
					index2 = 0;
				}
				Structure2DPole structure2DPole = poleList[index];
				Structure2DPole structure2DPole2 = poleList[index2];
				double dSAngle = 0.0;
				double dEAngle = 0.0;
				structure2DPole.GetAngle(node.Position, ref dSAngle);
				structure2DPole2.GetAngle(node.Position, ref dEAngle);
				if (Geometry.IsEqual(Geometry.BetweenTheAngles(dSAngle, dEAngle, true), Math.PI, 0.0001))
				{
					this.OperateVariableCross_SectionPoleSideline(node.Position, ref structure2DPole, ref structure2DPole2);
				}
				else
				{
					this.TrimPoleSideline(node.Position, ref structure2DPole, ref structure2DPole2);
				}
			}
		}

		protected void TrimAllNode(ref List<Structure2DNode> theNodes)
		{
			foreach (Structure2DNode node in theNodes)
			{
				this.TrimOneNode(node);
			}
			for (int i = 0; i < theNodes.Count; i++)
			{
				Structure2DNode structure2DNode = theNodes[i];
				XYZ position = structure2DNode.Position;
				foreach (Structure2DPole structure2DPole in structure2DNode.PoleList)
				{
					bool flag = structure2DPole.IsValidSideLineOfPositive() != Structure2DPole._tagSideLineValidType._Valide;
					Structure2DPole._tagSideLineValidType tagSideLineValidType = structure2DPole.IsValidSideLineOfNegative();
					if (flag || tagSideLineValidType != Structure2DPole._tagSideLineValidType._Valide)
					{
						int num = this.FindNodeIndexByPos(theNodes, structure2DPole.CurOutNodePosition(position));
						if (num != -1)
						{
							Structure2DNode structure2DNode2 = theNodes[num];
							if (structure2DNode2 != null)
							{
								theNodes.Add(this.Merge2ndRetrimNodes(structure2DNode, structure2DNode2));
								theNodes.RemoveAt(num);
								theNodes.RemoveAt(i);
								i--;
								break;
							}
						}
					}
				}
			}
		}

		protected Curve GetPoleSideLineByNodePosition(Structure2DPole pole, XYZ nodePosition, bool isPositive)
		{
			Curve result = null;
			if (isPositive)
			{
				XYZ xyz = pole.CurPositiveStartPoint(nodePosition);
				XYZ xyz2 = pole.CurPositiveEndPoint(nodePosition);
				if (xyz.IsAlmostEqualTo(xyz2))
				{
					return result;
				}
				if (pole.IsArcPole)
				{
					XYZ center = pole.Center;
					XYZ radianPnt = Geometry.CalculatMidPoint(xyz, xyz2, center, XYZ.BasisZ);
					return this.m_Revit.Application.Application.CreatYJKArc(xyz, xyz2, radianPnt);
				}
				try
				{
					return YJKLineEx.YJKGetBound(xyz, xyz2);
				}
				catch (Exception)
				{
					return null;
				}
			}
			XYZ xyz3 = pole.CurNegativeStartPoint(nodePosition);
			XYZ xyz4 = pole.CurNegativeEndPoint(nodePosition);
			if (xyz3.IsAlmostEqualTo(xyz4))
			{
				return result;
			}
			if (pole.IsArcPole)
			{
				XYZ center2 = pole.Center;
				XYZ radianPnt2 = Geometry.CalculatMidPoint(xyz3, xyz4, center2, XYZ.BasisZ);
				result = this.m_Revit.Application.Application.CreatYJKArc(xyz3, xyz4, radianPnt2);
			}
			else
			{
				try
				{
					result = YJKLineEx.YJKGetBound(xyz3, xyz4);
				}
				catch (Exception)
				{
					return null;
				}
			}
			return result;
		}

		protected void OperateVariableCross_SectionPoleSideline(XYZ position, ref Structure2DPole pole1, ref Structure2DPole pole2)
		{
			XYZ xyz = pole1.CurNegativeStartPoint(position);
			XYZ xyz2 = pole2.CurPositiveStartPoint(position);
			if (xyz.IsAlmostEqualTo(xyz2))
			{
				return;
			}
			double val = pole1.NegativeHalfWidth + pole1.PositiveHalfWidth;
			double val2 = pole2.NegativeHalfWidth + pole2.PositiveHalfWidth;
			if (Geometry.LessThan(val, val2))
			{
				pole1.SetCurVariableCross_SectionInNegativeStartPoint(position, null);
				pole2.SetCurVariableCross_SectionInPositiveStartPoint(position, new Edge(xyz, xyz2, 0.0));
				return;
			}
			pole1.SetCurVariableCross_SectionInNegativeStartPoint(position, new Edge(xyz, xyz2, 0.0));
			pole2.SetCurVariableCross_SectionInPositiveStartPoint(position, null);
		}

		protected void TrimPoleSideline(XYZ position, ref Structure2DPole pole1, ref Structure2DPole pole2)
		{
			Curve poleSideLineByNodePosition = this.GetPoleSideLineByNodePosition(pole1, position, false);
			Curve poleSideLineByNodePosition2 = this.GetPoleSideLineByNodePosition(pole2, position, true);
			if (null == poleSideLineByNodePosition || null == poleSideLineByNodePosition2)
			{
				return;
			}
			XYZ xyz = Geometry.IntersectWithTwoCurves(poleSideLineByNodePosition, poleSideLineByNodePosition2, position, true, true, this.m_Revit.Application.Application);
			if (xyz != null)
			{
				pole1.SetCurNegativeStartPoint(position, xyz);
				pole2.SetCurPositiveStartPoint(position, xyz);
				pole1.SetCurVariableCross_SectionInNegativeStartPoint(position, null);
				pole2.SetCurVariableCross_SectionInPositiveStartPoint(position, null);
				return;
			}
			this.OperateVariableCross_SectionPoleSideline(position, ref pole1, ref pole2);
		}

		protected Structure2DNode Merge2ndRetrimNodes(Structure2DNode node1, Structure2DNode node2)
		{
			List<int> indexList = node1.FindLinkPoleWithOtherNode(node2.Position);
			node1.RemoveSortEdges(indexList);
			List<int> indexList2 = node2.FindLinkPoleWithOtherNode(node1.Position);
			node2.RemoveSortEdges(indexList2);
			XYZ xyz = Geometry.CalculatMidPoint(node1.Position, node2.Position);
			List<Structure2DPole> list = new List<Structure2DPole>();
			foreach (Structure2DPole structure2DPole in node1.PoleList)
			{
				if (!structure2DPole.CurOutNodePosition(node1.Position).IsAlmostEqualTo(xyz))
				{
					structure2DPole.SetCurInNodePosition(node1.Position, xyz);
					list.Add(structure2DPole);
				}
			}
			foreach (Structure2DPole structure2DPole2 in node2.PoleList)
			{
				if (!structure2DPole2.CurOutNodePosition(node2.Position).IsAlmostEqualTo(xyz))
				{
					structure2DPole2.SetCurInNodePosition(node2.Position, xyz);
					list.Add(structure2DPole2);
				}
			}
			Structure2DNode structure2DNode = new Structure2DNode(xyz, list);
			structure2DNode.Tag = node1.Tag;
			this.TrimOneNode(structure2DNode);
			return structure2DNode;
		}

		protected Structure2DNode FindNodeByPos(List<Structure2DNode> theNodes, XYZ pos)
		{
			foreach (Structure2DNode structure2DNode in theNodes)
			{
				if (pos.IsAlmostEqualTo(structure2DNode.Position, 0.0001))
				{
					return structure2DNode;
				}
			}
			return null;
		}

		protected int FindNodeIndexByPos(List<Structure2DNode> theNodes, XYZ pos)
		{
			for (int i = 0; i < theNodes.Count; i++)
			{
				if (pos.IsAlmostEqualTo(theNodes[i].Position, 0.0001))
				{
					return i;
				}
			}
			return -1;
		}

		protected ExternalCommandData m_Revit;

		protected bool m_IsSearchEdgeLoops;
	}
}
